package wangwenjun.phase1.unchecked;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.concurrent.TimeUnit;

/**
 * @author ChangLiang
 * @date 2020/6/11
 */
@Slf4j
public class UncaughtExceptionHandlerTest {

    /**
     * 若既没有父ThreadGroup，也没有设置全局默认的UncaughtExceptionHandler，则会直接将异常的堆栈信息定向到System.err中
     */
    @Test
    @DisplayName("异常的堆栈信息定向到System.err")
    public void testEmptyExceptionHandler() throws InterruptedException {
        // getOutput current thread's thread group
        ThreadGroup mainGroup = Thread.currentThread().getThreadGroup();
        log.info("mainGroup name:{}", mainGroup.getName());
        log.info("mainGroup parent name:{}", mainGroup.getParent().getName());
        log.info("mainGroup parent parent name:{}", mainGroup.getParent().getParent()==null?"null":mainGroup.getParent().getParent().getName());

        final Thread thread = new Thread(() ->
        {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
            }

            // here will throw unchecked exception.
            try {
                System.out.println(1 / 0);
            } catch (Exception e) {
                log.error(ThreadUtil.exceptionToString(e));
            }
        }, "Test-Thread");

        thread.start();
        thread.join();
    }

    /**
     * 当线程在运行过程中出现异常时，JVM会调用dispatchUncaughtException方法，
     * 该方法会将对应的线程实例以及异常信息传递给回调接口
     */
    @Test
    @DisplayName("异常回调给派生此线程的parent thread Thread#setDefaultUncaughtExceptionHandler")
    public void testSetDefaultUncaughtExceptionHandler() throws InterruptedException {
        // 在main线程中 定义
        Thread.setDefaultUncaughtExceptionHandler((t,e)->{
            log.error("{} occur exception ", t.getName());
            log.error(ThreadUtil.exceptionToString(e));
        });

        final Thread thread = new Thread(() ->
        {
            try
            {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e)
            {
            }

            //here will throw unchecked exception.
            System.out.println(1 / 0);
        }, "Test-Thread");

        thread.start();
        thread.join();
    }

    @Test
    @DisplayName("异常回调给派生此线程的parent thread Thread#setUncaughtExceptionHandler")
    public void testSetUncaughtExceptionHandler() throws InterruptedException {
        final Thread thread = new Thread(() ->
        {
            try
            {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e)
            {
            }

            //here will throw unchecked exception.
            System.out.println(1 / 0);
        }, "Test-Thread");

        // 在main线程中 定义
        thread.setUncaughtExceptionHandler((t,e)->{
            log.error("{} occur exception ", t.getName());
            log.error(ThreadUtil.exceptionToString(e));
        });

        thread.start();
        thread.join();
    }
}
